package org.ch02.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ZQX
 * @date 2025-03-18
 */
public class BeanUtil {
    // 基本类型与包装类型的映射
    private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<>();

    static {
        primitiveWrapperMap.put(int.class, Integer.class);
        primitiveWrapperMap.put(long.class, Long.class);
        primitiveWrapperMap.put(double.class, Double.class);
        primitiveWrapperMap.put(float.class, Float.class);
        primitiveWrapperMap.put(boolean.class, Boolean.class);
        primitiveWrapperMap.put(char.class, Character.class);
        primitiveWrapperMap.put(byte.class, Byte.class);
        primitiveWrapperMap.put(short.class, Short.class);
    }

    /**
     * 创建任意类型的对象
     *
     * @param clazz 目标类的 Class 对象
     * @param args  构造方法的参数
     * @param <T>   目标类型
     * @return 创建的对象
     * @throws Exception 如果创建失败
     */
    public static <T> T createInstance(Class<T> clazz, Object... args) throws Exception {
        if (clazz == null) {
            throw new IllegalArgumentException("Class cannot be null");
        }

        // 获取所有构造方法
        Constructor<?>[] constructors = clazz.getConstructors();

        // 遍历构造方法，找到匹配的构造方法
        for (Constructor<?> constructor : constructors) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();

            // 如果参数数量不匹配，跳过
            if (parameterTypes.length != args.length) {
                continue;
            }

            // 检查参数类型是否匹配
            if (isMatch(parameterTypes, args)) {
                // 创建对象
                return (T) constructor.newInstance(convertArgs(parameterTypes, args));
            }
        }

        throw new NoSuchMethodException("No matching constructor found for class: " + clazz.getName());
    }

    public static <T> T invokeMethod(Class<T> clazz, String method, Object... args) throws Exception {
        if (clazz == null) {
            throw new IllegalArgumentException("Class cannot be null");
        }

        // 获取所有构造方法
        Method[] methods = clazz.getMethods();

        // 遍历构造方法，找到匹配的构造方法
        for (Method m : methods) {
            Class<?>[] parameterTypes = m.getParameterTypes();

            // 如果参数数量不匹配，跳过
            if (parameterTypes.length != args.length) {
                continue;
            }

            // 检查参数类型是否匹配
            if (isMatch(parameterTypes, args)) {
                // 创建对象
                return (T) m.invoke(clazz.getConstructor().newInstance(), convertArgs(parameterTypes, args));
            }
        }

        throw new NoSuchMethodException("No matching constructor found for class: " + clazz.getName());
    }

    /**
     * 检查参数类型是否匹配
     *
     * @param parameterTypes 构造方法的参数类型
     * @param args           实际参数
     * @return 是否匹配
     */
    private static boolean isMatch(Class<?>[] parameterTypes, Object[] args) {
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> paramType = parameterTypes[i];
            Object arg = args[i];

            // 如果参数为 null，跳过类型检查
            if (arg == null) {
                continue;
            }

            // 检查类型是否匹配，包括基本类型和包装类型的兼容性
            if (!isAssignable(paramType, arg.getClass())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查类型是否兼容（包括基本类型和包装类型）
     *
     * @param targetType 目标类型
     * @param sourceType 源类型
     * @return 是否兼容
     */
    private static boolean isAssignable(Class<?> targetType, Class<?> sourceType) {
        // 如果目标类型是基本类型，检查源类型是否是对应的包装类型
        if (targetType.isPrimitive()) {
            Class<?> wrapperType = primitiveWrapperMap.get(targetType);
            return wrapperType != null && wrapperType.equals(sourceType);
        }

        // 如果目标类型是包装类型，检查源类型是否是对应的基本类型
        if (sourceType.isPrimitive()) {
            Class<?> wrapperType = primitiveWrapperMap.get(sourceType);
            return wrapperType != null && wrapperType.equals(targetType);
        }

        // 普通类型检查
        return targetType.isAssignableFrom(sourceType);
    }

    /**
     * 转换参数类型（将基本类型转换为包装类型）
     *
     * @param parameterTypes 构造方法的参数类型
     * @param args           实际参数
     * @return 转换后的参数
     */
    private static Object[] convertArgs(Class<?>[] parameterTypes, Object[] args) {
        Object[] convertedArgs = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            Class<?> paramType = parameterTypes[i];
            Object arg = args[i];

            // 如果参数为 null，直接传递
            if (arg == null) {
                convertedArgs[i] = null;
                continue;
            }

            // 如果目标类型是基本类型，将包装类型转换为基本类型
            if (paramType.isPrimitive()) {
                Class<?> wrapperType = primitiveWrapperMap.get(paramType);
                if (wrapperType != null && wrapperType.equals(arg.getClass())) {
                    // 使用反射获取基本类型的值 - 调用包装类对象的 xxxValue 方法，把包装类型转换为对应的基本类型
                    try {
                        convertedArgs[i] = wrapperType.getMethod(paramType.getName() + "Value").invoke(arg);
                    } catch (Exception e) {
                        throw new RuntimeException("Failed to convert wrapper type to primitive type", e);
                    }
                }
            } else {
                convertedArgs[i] = arg;
            }
        }
        return convertedArgs;
    }
}
